In programming languages, such as C, C++, and assembly language, among others, a macro is a name that defines a set of instructions that are substituted for the macro name wherever the name appears in a program (a process called macro expansion) when the program is compiled or assembled. Macros are similar to functions in that they can take arguments and in that they can represent lengthier sets of instructions. Unlike functions, macros are replaced by the actual instructions they represent when the program is prepared for execution; function instructions are copied into a program only once. (See, Microsoft Computer Dictionary, Fourth Edition, page 278, Microsoft Press (1999).) In C and C++ programming languages, for example, macros can be defined in “#define” preprocessor directives.
A statement in source code that defines a macro is herein referred to as a macro definition. A source code statement that uses or contains a macro is referred to as a macro statement. The instructions resulting from the process of macro expansion of a macro is referred to herein as an expanded macro or also the macro's expansion.
The process of macro expansion conventionally is performed during or as a preprocess of compiling or assembling the program. The developer prepares the source file or files for the program, and inputs the source files to the compiler or assembler. The compiler or assembler produces object files, in which any macros are fully expanded and translated into object code form. Apart from the final object file or files resulting from the compilation, information as to the macro expansion of any individual macro is not kept. Accordingly, it can be very difficult for the developer to determine which set of object code instructions in the object code files were produced by macro expansion and compilation/assembly of respective macros in the source files.
Moreover, macros often are defined in terms of other macros. The macro expansion process therefore can often involve a nested sequence of macro expansions. In commercially significant software projects, macros are not uncommonly defined with 15 to 20 levels of nesting. This creates further difficulty for the developer to determine exactly how individual macros in the source code were expanded during compilation or assembly simply by examining the source files and resulting object files.
There are currently also preprocessors available for some programming languages, which perform macro expansion, among other analyses. Again, the developer inputs the source files to the preprocessor. The preprocessor outputs a macro-expanded version of the source files, in which any macros are fully expanded without being translated to object code. In this case, the macros are present in the original version of the source files, but only the resulting replacement instructions are present in the macro-expanded version. Accordingly, it remains difficult for developer to determine which set of instructions in the macro-expanded version of the source files result from macro expansion of particular macros in the original source files. Further, it can be particularly difficult in the case of nested macro definitions to determine the effect of intermediate macros in a sequence of nested macro definitions.
Further, many compilers and static source code analysis tools report errors that occur during compilation or static analysis by line number of the program's source files. Any macros on this line of the source file, however, appear in their original form, prior to macro expansion. The developer therefore has a difficult time determining the set of instructions produced during macro expansion from the macros.